home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / tk8.0 / unix / tkUnixScrlbr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-15  |  13.5 KB  |  477 lines  |  [TEXT/CWIE]

  1. /* 
  2.  * tkUnixScrollbar.c --
  3.  *
  4.  *    This file implements the Unix specific portion of the scrollbar
  5.  *    widget.
  6.  *
  7.  * Copyright (c) 1996 by Sun Microsystems, Inc.
  8.  *
  9.  * See the file "license.terms" for information on usage and redistribution
  10.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  *
  12.  * SCCS: @(#) tkUnixScrlbr.c 1.8 96/12/10 20:05:07
  13.  */
  14.  
  15. #include "tkScrollbar.h"
  16.  
  17. /*
  18.  * Minimum slider length, in pixels (designed to make sure that the slider
  19.  * is always easy to grab with the mouse).
  20.  */
  21.  
  22. #define MIN_SLIDER_LENGTH    5
  23.  
  24. /*
  25.  * Declaration of Unix specific scrollbar structure.
  26.  */
  27.  
  28. typedef struct UnixScrollbar {
  29.     TkScrollbar info;        /* Generic scrollbar info. */
  30.     GC troughGC;        /* For drawing trough. */
  31.     GC copyGC;            /* Used for copying from pixmap onto screen. */
  32. } UnixScrollbar;
  33.  
  34. /*
  35.  * The class procedure table for the scrollbar widget.
  36.  */
  37.  
  38. TkClassProcs tkpScrollbarProcs = { 
  39.     NULL,            /* createProc. */
  40.     NULL,            /* geometryProc. */
  41.     NULL            /* modalProc. */
  42. };
  43.  
  44.  
  45. /*
  46.  *----------------------------------------------------------------------
  47.  *
  48.  * TkpCreateScrollbar --
  49.  *
  50.  *    Allocate a new TkScrollbar structure.
  51.  *
  52.  * Results:
  53.  *    Returns a newly allocated TkScrollbar structure.
  54.  *
  55.  * Side effects:
  56.  *    Registers an event handler for the widget.
  57.  *
  58.  *----------------------------------------------------------------------
  59.  */
  60.  
  61. TkScrollbar *
  62. TkpCreateScrollbar(tkwin)
  63.     Tk_Window tkwin;
  64. {
  65.     UnixScrollbar *scrollPtr = (UnixScrollbar *)ckalloc(sizeof(UnixScrollbar));
  66.     scrollPtr->troughGC = None;
  67.     scrollPtr->copyGC = None;
  68.  
  69.     Tk_CreateEventHandler(tkwin,
  70.         ExposureMask|StructureNotifyMask|FocusChangeMask,
  71.         TkScrollbarEventProc, (ClientData) scrollPtr);
  72.  
  73.     return (TkScrollbar *) scrollPtr;
  74. }
  75.  
  76. /*
  77.  *--------------------------------------------------------------
  78.  *
  79.  * TkpDisplayScrollbar --
  80.  *
  81.  *    This procedure redraws the contents of a scrollbar window.
  82.  *    It is invoked as a do-when-idle handler, so it only runs
  83.  *    when there's nothing else for the application to do.
  84.  *
  85.  * Results:
  86.  *    None.
  87.  *
  88.  * Side effects:
  89.  *    Information appears on the screen.
  90.  *
  91.  *--------------------------------------------------------------
  92.  */
  93.  
  94. void
  95. TkpDisplayScrollbar(clientData)
  96.     ClientData clientData;    /* Information about window. */
  97. {
  98.     register TkScrollbar *scrollPtr = (TkScrollbar *) clientData;
  99.     register Tk_Window tkwin = scrollPtr->tkwin;
  100.     XPoint points[7];
  101.     Tk_3DBorder border;
  102.     int relief, width, elementBorderWidth;
  103.     Pixmap pixmap;
  104.  
  105.     if ((scrollPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
  106.     goto done;
  107.     }
  108.  
  109.     if (scrollPtr->vertical) {
  110.     width = Tk_Width(tkwin) - 2*scrollPtr->inset;
  111.     } else {
  112.     width = Tk_Height(tkwin) - 2*scrollPtr->inset;
  113.     }
  114.     elementBorderWidth = scrollPtr->elementBorderWidth;
  115.     if (elementBorderWidth < 0) {
  116.     elementBorderWidth = scrollPtr->borderWidth;
  117.     }
  118.  
  119.     /*
  120.      * In order to avoid screen flashes, this procedure redraws
  121.      * the scrollbar in a pixmap, then copies the pixmap to the
  122.      * screen in a single operation.  This means that there's no
  123.      * point in time where the on-sreen image has been cleared.
  124.      */
  125.  
  126.     pixmap = Tk_GetPixmap(scrollPtr->display, Tk_WindowId(tkwin),
  127.         Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin));
  128.  
  129.     if (scrollPtr->highlightWidth != 0) {
  130.     GC gc;
  131.  
  132.     if (scrollPtr->flags & GOT_FOCUS) {
  133.         gc = Tk_GCForColor(scrollPtr->highlightColorPtr, pixmap);
  134.     } else {
  135.         gc = Tk_GCForColor(scrollPtr->highlightBgColorPtr, pixmap);
  136.     }
  137.     Tk_DrawFocusHighlight(tkwin, gc, scrollPtr->highlightWidth, pixmap);
  138.     }
  139.     Tk_Draw3DRectangle(tkwin, pixmap, scrollPtr->bgBorder,
  140.         scrollPtr->highlightWidth, scrollPtr->highlightWidth,
  141.         Tk_Width(tkwin) - 2*scrollPtr->highlightWidth,
  142.         Tk_Height(tkwin) - 2*scrollPtr->highlightWidth,
  143.         scrollPtr->borderWidth, scrollPtr->relief);
  144.     XFillRectangle(scrollPtr->display, pixmap,
  145.         ((UnixScrollbar*)scrollPtr)->troughGC,
  146.         scrollPtr->inset, scrollPtr->inset,
  147.         (unsigned) (Tk_Width(tkwin) - 2*scrollPtr->inset),
  148.         (unsigned) (Tk_Height(tkwin) - 2*scrollPtr->inset));
  149.  
  150.     /*
  151.      * Draw the top or left arrow.  The coordinates of the polygon
  152.      * points probably seem odd, but they were carefully chosen with
  153.      * respect to X's rules for filling polygons.  These point choices
  154.      * cause the arrows to just fill the narrow dimension of the
  155.      * scrollbar and be properly centered.
  156.      */
  157.  
  158.     if (scrollPtr->activeField == TOP_ARROW) {
  159.     border = scrollPtr->activeBorder;
  160.     relief = scrollPtr->activeField == TOP_ARROW ? scrollPtr->activeRelief
  161.         : TK_RELIEF_RAISED;
  162.     } else {
  163.     border = scrollPtr->bgBorder;
  164.     relief = TK_RELIEF_RAISED;
  165.     }
  166.     if (scrollPtr->vertical) {
  167.     points[0].x = scrollPtr->inset - 1;
  168.     points[0].y = scrollPtr->arrowLength + scrollPtr->inset - 1;
  169.     points[1].x = width + scrollPtr->inset;
  170.     points[1].y = points[0].y;
  171.     points[2].x = width/2 + scrollPtr->inset;
  172.     points[2].y = scrollPtr->inset - 1;
  173.     Tk_Fill3DPolygon(tkwin, pixmap, border, points, 3,
  174.         elementBorderWidth, relief);
  175.     } else {
  176.     points[0].x = scrollPtr->arrowLength + scrollPtr->inset - 1;
  177.     points[0].y = scrollPtr->inset - 1;
  178.     points[1].x = scrollPtr->inset;
  179.     points[1].y = width/2 + scrollPtr->inset;
  180.     points[2].x = points[0].x;
  181.     points[2].y = width + scrollPtr->inset;
  182.     Tk_Fill3DPolygon(tkwin, pixmap, border, points, 3,
  183.         elementBorderWidth, relief);
  184.     }
  185.  
  186.     /*
  187.      * Display the bottom or right arrow.
  188.      */
  189.  
  190.     if (scrollPtr->activeField == BOTTOM_ARROW) {
  191.     border = scrollPtr->activeBorder;
  192.     relief = scrollPtr->activeField == BOTTOM_ARROW
  193.         ? scrollPtr->activeRelief : TK_RELIEF_RAISED;
  194.     } else {
  195.     border = scrollPtr->bgBorder;
  196.     relief = TK_RELIEF_RAISED;
  197.     }
  198.     if (scrollPtr->vertical) {
  199.     points[0].x = scrollPtr->inset;
  200.     points[0].y = Tk_Height(tkwin) - scrollPtr->arrowLength
  201.         - scrollPtr->inset + 1;
  202.     points[1].x = width/2 + scrollPtr->inset;
  203.     points[1].y = Tk_Height(tkwin) - scrollPtr->inset;
  204.     points[2].x = width + scrollPtr->inset;
  205.     points[2].y = points[0].y;
  206.     Tk_Fill3DPolygon(tkwin, pixmap, border,
  207.         points, 3, elementBorderWidth, relief);
  208.     } else {
  209.     points[0].x = Tk_Width(tkwin) - scrollPtr->arrowLength
  210.         - scrollPtr->inset + 1;
  211.     points[0].y = scrollPtr->inset - 1;
  212.     points[1].x = points[0].x;
  213.     points[1].y = width + scrollPtr->inset;
  214.     points[2].x = Tk_Width(tkwin) - scrollPtr->inset;
  215.     points[2].y = width/2 + scrollPtr->inset;
  216.     Tk_Fill3DPolygon(tkwin, pixmap, border,
  217.         points, 3, elementBorderWidth, relief);
  218.     }
  219.  
  220.     /*
  221.      * Display the slider.
  222.      */
  223.  
  224.     if (scrollPtr->activeField == SLIDER) {
  225.     border = scrollPtr->activeBorder;
  226.     relief = scrollPtr->activeField == SLIDER ? scrollPtr->activeRelief
  227.         : TK_RELIEF_RAISED;
  228.     } else {
  229.     border = scrollPtr->bgBorder;
  230.     relief = TK_RELIEF_RAISED;
  231.     }
  232.     if (scrollPtr->vertical) {
  233.     Tk_Fill3DRectangle(tkwin, pixmap, border,
  234.         scrollPtr->inset, scrollPtr->sliderFirst,
  235.         width, scrollPtr->sliderLast - scrollPtr->sliderFirst,
  236.         elementBorderWidth, relief);
  237.     } else {
  238.     Tk_Fill3DRectangle(tkwin, pixmap, border,
  239.         scrollPtr->sliderFirst, scrollPtr->inset,
  240.         scrollPtr->sliderLast - scrollPtr->sliderFirst, width,
  241.         elementBorderWidth, relief);
  242.     }
  243.  
  244.     /*
  245.      * Copy the information from the off-screen pixmap onto the screen,
  246.      * then delete the pixmap.
  247.      */
  248.  
  249.     XCopyArea(scrollPtr->display, pixmap, Tk_WindowId(tkwin),
  250.         ((UnixScrollbar*)scrollPtr)->copyGC, 0, 0,
  251.         (unsigned) Tk_Width(tkwin), (unsigned) Tk_Height(tkwin), 0, 0);
  252.     Tk_FreePixmap(scrollPtr->display, pixmap);
  253.  
  254.     done:
  255.     scrollPtr->flags &= ~REDRAW_PENDING;
  256. }
  257.  
  258. /*
  259.  *----------------------------------------------------------------------
  260.  *
  261.  * TkpComputeScrollbarGeometry --
  262.  *
  263.  *    After changes in a scrollbar's size or configuration, this
  264.  *    procedure recomputes various geometry information used in
  265.  *    displaying the scrollbar.
  266.  *
  267.  * Results:
  268.  *    None.
  269.  *
  270.  * Side effects:
  271.  *    The scrollbar will be displayed differently.
  272.  *
  273.  *----------------------------------------------------------------------
  274.  */
  275.  
  276. extern void
  277. TkpComputeScrollbarGeometry(scrollPtr)
  278.     register TkScrollbar *scrollPtr;    /* Scrollbar whose geometry may
  279.                      * have changed. */
  280. {
  281.     int width, fieldLength;
  282.  
  283.     if (scrollPtr->highlightWidth < 0) {
  284.     scrollPtr->highlightWidth = 0;
  285.     }
  286.     scrollPtr->inset = scrollPtr->highlightWidth + scrollPtr->borderWidth;
  287.     width = (scrollPtr->vertical) ? Tk_Width(scrollPtr->tkwin)
  288.         : Tk_Height(scrollPtr->tkwin);
  289.     scrollPtr->arrowLength = width - 2*scrollPtr->inset + 1;
  290.     fieldLength = (scrollPtr->vertical ? Tk_Height(scrollPtr->tkwin)
  291.         : Tk_Width(scrollPtr->tkwin))
  292.         - 2*(scrollPtr->arrowLength + scrollPtr->inset);
  293.     if (fieldLength < 0) {
  294.     fieldLength = 0;
  295.     }
  296.     scrollPtr->sliderFirst = fieldLength*scrollPtr->firstFraction;
  297.     scrollPtr->sliderLast = fieldLength*scrollPtr->lastFraction;
  298.  
  299.     /*
  300.      * Adjust the slider so that some piece of it is always
  301.      * displayed in the scrollbar and so that it has at least
  302.      * a minimal width (so it can be grabbed with the mouse).
  303.      */
  304.  
  305.     if (scrollPtr->sliderFirst > (fieldLength - 2*scrollPtr->borderWidth)) {
  306.     scrollPtr->sliderFirst = fieldLength - 2*scrollPtr->borderWidth;
  307.     }
  308.     if (scrollPtr->sliderFirst < 0) {
  309.     scrollPtr->sliderFirst = 0;
  310.     }
  311.     if (scrollPtr->sliderLast < (scrollPtr->sliderFirst
  312.         + MIN_SLIDER_LENGTH)) {
  313.     scrollPtr->sliderLast = scrollPtr->sliderFirst + MIN_SLIDER_LENGTH;
  314.     }
  315.     if (scrollPtr->sliderLast > fieldLength) {
  316.     scrollPtr->sliderLast = fieldLength;
  317.     }
  318.     scrollPtr->sliderFirst += scrollPtr->arrowLength + scrollPtr->inset;
  319.     scrollPtr->sliderLast += scrollPtr->arrowLength + scrollPtr->inset;
  320.  
  321.     /*
  322.      * Register the desired geometry for the window (leave enough space
  323.      * for the two arrows plus a minimum-size slider, plus border around
  324.      * the whole window, if any).  Then arrange for the window to be
  325.      * redisplayed.
  326.      */
  327.  
  328.     if (scrollPtr->vertical) {
  329.     Tk_GeometryRequest(scrollPtr->tkwin,
  330.         scrollPtr->width + 2*scrollPtr->inset,
  331.         2*(scrollPtr->arrowLength + scrollPtr->borderWidth
  332.         + scrollPtr->inset));
  333.     } else {
  334.     Tk_GeometryRequest(scrollPtr->tkwin,
  335.         2*(scrollPtr->arrowLength + scrollPtr->borderWidth
  336.         + scrollPtr->inset), scrollPtr->width + 2*scrollPtr->inset);
  337.     }
  338.     Tk_SetInternalBorder(scrollPtr->tkwin, scrollPtr->inset);
  339. }
  340.  
  341. /*
  342.  *----------------------------------------------------------------------
  343.  *
  344.  * TkpDestroyScrollbar --
  345.  *
  346.  *    Free data structures associated with the scrollbar control.
  347.  *
  348.  * Results:
  349.  *    None.
  350.  *
  351.  * Side effects:
  352.  *    Frees the GCs associated with the scrollbar.
  353.  *
  354.  *----------------------------------------------------------------------
  355.  */
  356.  
  357. void
  358. TkpDestroyScrollbar(scrollPtr)
  359.     TkScrollbar *scrollPtr;
  360. {
  361.     UnixScrollbar *unixScrollPtr = (UnixScrollbar *)scrollPtr;
  362.  
  363.     if (unixScrollPtr->troughGC != None) {
  364.     Tk_FreeGC(scrollPtr->display, unixScrollPtr->troughGC);
  365.     }
  366.     if (unixScrollPtr->copyGC != None) {
  367.     Tk_FreeGC(scrollPtr->display, unixScrollPtr->copyGC);
  368.     }
  369. }
  370.  
  371. /*
  372.  *----------------------------------------------------------------------
  373.  *
  374.  * TkpConfigureScrollbar --
  375.  *
  376.  *    This procedure is called after the generic code has finished
  377.  *    processing configuration options, in order to configure
  378.  *    platform specific options.
  379.  *
  380.  * Results:
  381.  *    None.
  382.  *
  383.  * Side effects:
  384.  *    Configuration info may get changed.
  385.  *
  386.  *----------------------------------------------------------------------
  387.  */
  388.  
  389. void
  390. TkpConfigureScrollbar(scrollPtr)
  391.     register TkScrollbar *scrollPtr;    /* Information about widget;  may or
  392.                      * may not already have values for
  393.                      * some fields. */
  394. {
  395.     XGCValues gcValues;
  396.     GC new;
  397.     UnixScrollbar *unixScrollPtr = (UnixScrollbar *) scrollPtr;
  398.  
  399.     Tk_SetBackgroundFromBorder(scrollPtr->tkwin, scrollPtr->bgBorder);
  400.  
  401.     gcValues.foreground = scrollPtr->troughColorPtr->pixel;
  402.     new = Tk_GetGC(scrollPtr->tkwin, GCForeground, &gcValues);
  403.     if (unixScrollPtr->troughGC != None) {
  404.     Tk_FreeGC(scrollPtr->display, unixScrollPtr->troughGC);
  405.     }
  406.     unixScrollPtr->troughGC = new;
  407.     if (unixScrollPtr->copyGC == None) {
  408.     gcValues.graphics_exposures = False;
  409.     unixScrollPtr->copyGC = Tk_GetGC(scrollPtr->tkwin, GCGraphicsExposures,
  410.         &gcValues);
  411.     }
  412. }
  413.  
  414. /*
  415.  *--------------------------------------------------------------
  416.  *
  417.  * TkpScrollbarPosition --
  418.  *
  419.  *    Determine the scrollbar element corresponding to a
  420.  *    given position.
  421.  *
  422.  * Results:
  423.  *    One of TOP_ARROW, TOP_GAP, etc., indicating which element
  424.  *    of the scrollbar covers the position given by (x, y).  If
  425.  *    (x,y) is outside the scrollbar entirely, then OUTSIDE is
  426.  *    returned.
  427.  *
  428.  * Side effects:
  429.  *    None.
  430.  *
  431.  *--------------------------------------------------------------
  432.  */
  433.  
  434. int
  435. TkpScrollbarPosition(scrollPtr, x, y)
  436.     register TkScrollbar *scrollPtr;    /* Scrollbar widget record. */
  437.     int x, y;                /* Coordinates within scrollPtr's
  438.                      * window. */
  439. {
  440.     int length, width, tmp;
  441.  
  442.     if (scrollPtr->vertical) {
  443.     length = Tk_Height(scrollPtr->tkwin);
  444.     width = Tk_Width(scrollPtr->tkwin);
  445.     } else {
  446.     tmp = x;
  447.     x = y;
  448.     y = tmp;
  449.     length = Tk_Width(scrollPtr->tkwin);
  450.     width = Tk_Height(scrollPtr->tkwin);
  451.     }
  452.  
  453.     if ((x < scrollPtr->inset) || (x >= (width - scrollPtr->inset))
  454.         || (y < scrollPtr->inset) || (y >= (length - scrollPtr->inset))) {
  455.     return OUTSIDE;
  456.     }
  457.  
  458.     /*
  459.      * All of the calculations in this procedure mirror those in
  460.      * TkpDisplayScrollbar.  Be sure to keep the two consistent.
  461.      */
  462.  
  463.     if (y < (scrollPtr->inset + scrollPtr->arrowLength)) {
  464.     return TOP_ARROW;
  465.     }
  466.     if (y < scrollPtr->sliderFirst) {
  467.     return TOP_GAP;
  468.     }
  469.     if (y < scrollPtr->sliderLast) {
  470.     return SLIDER;
  471.     }
  472.     if (y >= (length - (scrollPtr->arrowLength + scrollPtr->inset))) {
  473.     return BOTTOM_ARROW;
  474.     }
  475.     return BOTTOM_GAP;
  476. }
  477.